#include "Camera.h"

#include "JPhysicsMaths.h"
#include "JPQuat.h"

//------------------------------------------------
Camera::Camera():
m_lookat( JPVec3(0.0f, 0.0f, 0.0f) ),
m_position( JPVec3(0.0f,0.0f,-400.0f) ),
m_up( JPVec3(0.0f,1.0f,0.0f) ),
m_mode(THIRD)
{
	JPVec3 axis = JPVec3(1.0f,0.0f,0.0f);
	rotateCamera3(PI/6.0f, axis);

	axis = JPVec3(0.0f,1.0f,0.0f);
	rotateCamera3(-2.0f*PI/3.0f, axis);

	changezoom(-300);
}
//------------------------------------------------
void Camera::update(const JPVec2 &mouseDir)
{
	// axis to rotate around will be the normal to the Up vector and
	// vector from position to lookat.
	JPVec3 UP(0.0f,1.0f,0.0f);
	JPVec3 v = m_lookat - m_position;
	JPVec3 axis = v.cross(UP);

	axis.normalise();
	
	JPVec3 from, to;
	if(m_mode)  // if first person mode
	{
		rotateCameraFP(mouseDir.y, axis); // Rotate around the local x axis
		rotateCameraFP(mouseDir.x, UP);   // Rotate around the UP vector
	}
	else // else god mode
	{
		rotateCamera3(mouseDir.y, axis);
		rotateCamera3(mouseDir.x, UP);
	}
}
//------------------------------------------------
void Camera::setMode(bool mode)
{
	m_mode = mode;
	if(m_mode)
	{
		m_lookat	= JPVec3(150.0f, 20.0f, 150.0f);
		m_position	= JPVec3(0.0f,20.0f,0.0f);
	}
	else
	{
		m_lookat	= JPVec3(0.0f, 0.0f, 0.0f);
		m_position	= JPVec3(0.0f,0.0f,-400.0f);

		JPVec3 axis = JPVec3(-1.0f,0.0f,0.0f);
		rotateCamera3(PI/9.0f,axis);

		m_mode = THIRD;
	}
}
//------------------------------------------------
void Camera::moveForward(float speed)
{
	// lookat projected to y level of position to restrict movement to the x-z plane
	JPVec3 v(m_lookat.x, m_position.y, m_lookat.z); 

	// get the direction to move the camera
	JPVec3 movementDir = v - m_position;          
	movementDir.normalise();   

	// update new position and lookat
	m_lookat   = m_lookat   + movementDir*speed;       
	m_position = m_position + movementDir*speed;
}
//------------------------------------------------
void Camera::strafeCam(float speed)
{
	JPVec3 v(m_lookat.x, m_position.y, m_lookat.z);

	// get perpendicular of x-z and mvoe camera in this direction
	JPVec3 forwardDir = v - m_position;
	JPVec3 strafeDir(forwardDir.z, forwardDir.y, -forwardDir.x);
	strafeDir.normalise();

	m_lookat   = m_lookat   + strafeDir*speed;  // update new position and lookat
	m_position = m_position + strafeDir*speed;
}
//------------------------------------------------
void Camera::changezoom(float zoom)
{
	JPVec3 v = m_lookat - m_position;
	v.normalise();
	m_position = m_position + v*zoom;
}
//------------------------------------------------
void Camera::rotateCamera3(float angle, const JPVec3 &axis)
{
	JPQuat rot(axis, angle);

	m_position = m_lookat + rot.rotateVec( m_position - m_lookat );
}
//------------------------------------------------
void Camera::rotateCameraFP(float angle, const JPVec3 &axis)
{
	JPQuat rot(axis, angle);

	m_lookat = m_position + rot.rotateVec( m_lookat - m_position );
}
